/**
 * 页面：3D 展馆（自由漫游）
 * 功能：基于 Three.js 的画廊空间，支持 PointerLock 控制、碰撞与灯光；点击相框查看大图
 * 组成：场景/相框/灯光/行走物理与障碍、覆盖层进入提示与图片查看器
 */
import React, { useState } from 'react'
import { useEffect, useRef } from 'react'
import * as THREE from 'three'
import { PointerLockControls } from 'three/examples/jsm/controls/PointerLockControls'
 

// 示例图片库 - 可以替换为实际图片URL
const IMAGE_POOL = [
  'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=800',
  'https://images.unsplash.com/photo-1469474968028-56623f02e42e?w=800',
  'https://images.unsplash.com/photo-1501594907352-04cda38ebc29?w=800',
  'https://images.unsplash.com/photo-1473448912268-2022ce9509d8?w=800',
  'https://images.unsplash.com/photo-1447752875215-b2761acb3c5d?w=800',
  'https://images.unsplash.com/photo-1416879595882-3373a0480b5b?w=800',
  'https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=800',
  'https://images.unsplash.com/photo-1464822759023-fed622ff2c3b?w=800',
  'https://images.unsplash.com/photo-1497436072909-60f360e1d4b1?w=800',
  'https://images.unsplash.com/photo-1518837695005-2083093ee35b?w=800',
  'https://images.unsplash.com/photo-1500382017468-9049fed747ef?w=800',
  'https://images.unsplash.com/photo-1527482797697-8795b05a13fe?w=800',
  'https://images.unsplash.com/photo-1519682337058-a94d519337bc?w=800',
  'https://images.unsplash.com/photo-1449824913935-59a10b8d2000?w=800',
  'https://images.unsplash.com/photo-1493246507139-91e8fad9978e?w=800',
  'https://images.unsplash.com/photo-1516594798947-e65505dbb29d?w=800',
]

function Index() {
  const mountRef = useRef<HTMLDivElement>(null)
  const overlayRef = useRef<HTMLDivElement>(null)
  const [selectedImage, setSelectedImage] = useState<string | null>(null)
  const [position, setPosition] = useState<{ x: number; y: number; z: number }>({ x: 0, y: 1.7, z: 6 })
  const [nearbyFrame, setNearbyFrame] = useState<{ imageUrl: string; distance: number } | null>(null)

  useEffect(() => {
    const container = mountRef.current
    if (!container) return

    const renderer = new THREE.WebGLRenderer({ antialias: true })
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
    renderer.setSize(window.innerWidth, window.innerHeight)
    renderer.shadowMap.enabled = true
    container.appendChild(renderer.domElement)

    const scene = new THREE.Scene()
    scene.background = new THREE.Color(0x0a1a2a)
    scene.fog = new THREE.Fog(0x0a1a2a, 40, 200)

    const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 500)
    camera.position.set(0, 1.7, 6)

    const hemi = new THREE.HemisphereLight(0x87ceff, 0x0a1020, 0.6)
    scene.add(hemi)
    const dir = new THREE.DirectionalLight(0xb7d7ff, 1.0)
    dir.position.set(10, 20, 10)
    dir.castShadow = true
    dir.shadow.mapSize.set(2048, 2048)
    scene.add(dir)

    const floor = new THREE.Mesh(
      new THREE.PlaneGeometry(200, 200),
      new THREE.MeshStandardMaterial({ color: 0xe9ebee, roughness: 0.2, metalness: 0.15 })
    )
    floor.rotation.x = -Math.PI / 2
    floor.receiveShadow = true
    scene.add(floor)

    const group = new THREE.Group()
    scene.add(group)

    const galleryW = 24
    const galleryH = 4.2
    const galleryD = 42
    const texLoader = new THREE.TextureLoader()

    const wallColor = 0xffffff
    const wallMat = new THREE.MeshStandardMaterial({ color: wallColor, roughness: 0.7, metalness: 0.05 })
    const leftWall = new THREE.Mesh(new THREE.PlaneGeometry(galleryD, galleryH), wallMat)
    leftWall.position.set(-galleryW/2, galleryH/2, -galleryD/2 + galleryD/2)
    leftWall.rotation.y = Math.PI/2
    group.add(leftWall)

    const rightWall = new THREE.Mesh(new THREE.PlaneGeometry(galleryD, galleryH), wallMat)
    rightWall.position.set(galleryW/2, galleryH/2, -galleryD/2 + galleryD/2)
    rightWall.rotation.y = -Math.PI/2
    group.add(rightWall)

    const backOpeningFrame = new THREE.Mesh(new THREE.PlaneGeometry(galleryW, galleryH), new THREE.MeshStandardMaterial({ color: 0xf7f7f7, roughness: 0.8 }))
    backOpeningFrame.position.set(0, galleryH/2, -galleryD)
    group.add(backOpeningFrame)

    const panoramaUrl = (window as any).PANORAMA_URL as string | undefined
    if (panoramaUrl) {
      const panoTex = texLoader.load(panoramaUrl)
      panoTex.colorSpace = THREE.SRGBColorSpace
      const pano = new THREE.Mesh(new THREE.PlaneGeometry(galleryW*2, galleryH*1.2), new THREE.MeshBasicMaterial({ map: panoTex }))
      pano.position.set(0, galleryH/2, -galleryD - 0.1)
      group.add(pano)
    }

    // Recessed ceiling light panels
    const lightRows = 6
    const panelsPerRow = 3
    const panelW = 3.0, panelH = 0.5
    const panelMat = new THREE.MeshStandardMaterial({ color: 0xffffff, emissive: 0xffffff, emissiveIntensity: 1.6, roughness: 0.1 })
    for (let r = 0; r < lightRows; r++) {
      const z = -galleryD + 4 + r * ((galleryD - 8) / (lightRows - 1))
      for (let c = 0; c < panelsPerRow; c++) {
        const x = -galleryW/3 + c * (galleryW/3)
        const panel = new THREE.Mesh(new THREE.PlaneGeometry(panelW, panelH), panelMat)
        panel.position.set(x, galleryH - 0.02, z)
        panel.rotation.x = Math.PI/2
        group.add(panel)
        const area = new THREE.RectAreaLight(0xffffff, 6, panelW, panelH)
        area.position.set(x, galleryH - 0.03, z)
        area.lookAt(x, galleryH - 1.0, z)
        scene.add(area)
      }
    }

    // Side wall wash lights (soft grazing effect)
    const sideLightL = new THREE.SpotLight(0xffffff, 0.6, 20, Math.PI/6, 0.6)
    sideLightL.position.set(-galleryW/4, galleryH-0.5, -galleryD/2)
    sideLightL.target.position.set(-galleryW/2, 1.5, -galleryD/2)
    scene.add(sideLightL, sideLightL.target)
    const sideLightR = sideLightL.clone(); sideLightR.position.x = galleryW/4; sideLightR.target.position.x = galleryW/2
    scene.add(sideLightR, sideLightR.target)

    // Frames on both walls
    const images: string[] = (window as any).WALL_IMAGES || []
    const dynamicObstacles: { pos: THREE.Vector2; half: THREE.Vector2 }[] = []
    const frameCountPerSide = 8
    const gap = 1.6
    const frameW = (galleryD - (frameCountPerSide + 1) * gap) / frameCountPerSide
    const frameH = frameW * 0.75
    
    // 随机选择图片池
    const allFrames = frameCountPerSide * 2
    const shuffledImages = [...IMAGE_POOL].sort(() => Math.random() - 0.5).slice(0, allFrames)
    
    // 存储所有相框的图片mesh，用于点击检测
    const frameMeshes: Array<{ mesh: THREE.Mesh, imageUrl: string }> = []

    const makeFrame = (centerX:number, z:number, facing:number, img?:string) => {
      const frameGroup = new THREE.Group()
      frameGroup.position.set(centerX, galleryH*0.6, z)
      frameGroup.rotation.y = facing
      const borderGeo = new THREE.PlaneGeometry(frameW, frameH)
      const borderMat = new THREE.MeshStandardMaterial({ color: 0x111111, roughness: 0.6, metalness: 0.1 })
      const border = new THREE.Mesh(borderGeo, borderMat)
      frameGroup.add(border)
      const innerGeo = new THREE.PlaneGeometry(frameW*0.92, frameH*0.92)
      const innerMat = new THREE.MeshStandardMaterial({ color: 0xffffff })
      const inner = new THREE.Mesh(innerGeo, innerMat)
      inner.position.z = 0.01
      frameGroup.add(inner)
      
      // 存储用于点击检测
      if (img) {
        const t = texLoader.load(img); t.colorSpace = THREE.SRGBColorSpace
        ;(inner.material as THREE.MeshStandardMaterial).map = t
        ;(inner.material as THREE.MeshStandardMaterial).needsUpdate = true
        frameMeshes.push({ mesh: inner, imageUrl: img })
      }
      
      group.add(frameGroup)
      // Add thin obstacle near the frame so player cannot get too close
      dynamicObstacles.push({ pos: new THREE.Vector2(centerX, z), half: new THREE.Vector2(0.18, frameW/2 + 0.05) })
    }
    for (let i = 0; i < frameCountPerSide; i++) {
      const z = -galleryD + gap + i * (frameW + gap) + frameW/2
      const leftImg = images[i] || shuffledImages[i]
      const rightImg = images[i + frameCountPerSide] || shuffledImages[i + frameCountPerSide]
      makeFrame(-galleryW/2 + 0.03, z, Math.PI/2, leftImg)
      makeFrame( galleryW/2 - 0.03, z, -Math.PI/2, rightImg)
    }

    // Minimal pedestals
    const plinthMat = new THREE.MeshStandardMaterial({ color: 0xffffff, roughness: 0.4 })
    const plinth1 = new THREE.Mesh(new THREE.BoxGeometry(1.4, 0.6, 1.0), plinthMat)
    plinth1.position.set(-4, 0.3, -galleryD*0.25)
    const plinth2 = new THREE.Mesh(new THREE.BoxGeometry(1.0, 0.5, 1.0), plinthMat)
    plinth2.position.set(3.2, 0.25, -galleryD*0.55)
    group.add(plinth1, plinth2)

    const controls = new PointerLockControls(camera, renderer.domElement)

    // 点击检测相关
    const raycaster = new THREE.Raycaster()
    const mouse = new THREE.Vector2()
    const MAX_INTERACT_DISTANCE = 3.0 // 最大交互距离：3米
    
    // 计算相机到相框的距离
    const getFrameDistance = (frameMesh: THREE.Mesh): number => {
      const frameWorldPos = new THREE.Vector3()
      frameMesh.getWorldPosition(frameWorldPos)
      return camera.position.distanceTo(frameWorldPos)
    }
    
    const handleClick = (event: MouseEvent) => {
      // 计算鼠标在归一化设备坐标中的位置
      mouse.x = (event.clientX / window.innerWidth) * 2 - 1
      mouse.y = -(event.clientY / window.innerHeight) * 2 + 1
      
      // 使用相机和鼠标位置更新射线
      raycaster.setFromCamera(mouse, camera)
      
      // 检测与相框的交叉
      const intersects = raycaster.intersectObjects(frameMeshes.map(f => f.mesh))
      
      if (intersects.length > 0) {
        // 找到被点击的相框
        const clickedFrame = frameMeshes.find(f => f.mesh === intersects[0].object)
        if (clickedFrame) {
          // 检查距离：只有在靠近照片时才能点击
          const distance = getFrameDistance(clickedFrame.mesh)
          
          if (distance <= MAX_INTERACT_DISTANCE) {
            // 距离足够近，可以查看照片
            setSelectedImage(clickedFrame.imageUrl)
          } else {
            // 距离太远，提示用户靠近
            console.log(`距离太远（${distance.toFixed(2)}米），请靠近照片后再点击`)
          }
        }
      }
    }
    
    renderer.domElement.addEventListener('click', handleClick)

    const overlay = overlayRef.current
    const lock = () => controls.lock()
    overlay?.addEventListener('click', lock)
    controls.addEventListener('lock', () => { if (overlay) overlay.style.display = 'none' })
    controls.addEventListener('unlock', () => { if (overlay) overlay.style.display = 'flex' })

    const keys = { w:false, a:false, s:false, d:false, space:false }
    const onKeyDown = (e: KeyboardEvent) => {
      if (e.code === 'KeyW') keys.w = true
      if (e.code === 'KeyA') keys.a = true
      if (e.code === 'KeyS') keys.s = true
      if (e.code === 'KeyD') keys.d = true
      if (e.code === 'Space') keys.space = true
    }
    const onKeyUp = (e: KeyboardEvent) => {
      if (e.code === 'KeyW') keys.w = false
      if (e.code === 'KeyA') keys.a = false
      if (e.code === 'KeyS') keys.s = false
      if (e.code === 'KeyD') keys.d = false
      if (e.code === 'Space') keys.space = false
    }
    window.addEventListener('keydown', onKeyDown)
    window.addEventListener('keyup', onKeyUp)

    const velocity = new THREE.Vector3()
    const direction = new THREE.Vector3()

    // 存储上一帧的位置（用于计算移动向量或其他用途）
    const prevPosition = new THREE.Vector3(camera.position.x, 0, camera.position.z)

    // Simple collision parameters
    const playerRadius = 0.4
    const wallClear = 0.6
    const bounds = {
      minX: -galleryW / 2 + playerRadius + wallClear,
      maxX:  galleryW / 2 - playerRadius - wallClear,
      minZ: -galleryD + playerRadius,
      maxZ:  6 - playerRadius,
    }
    // Obstacles: plinths defined above
    const obstacles = [
      { pos: new THREE.Vector2(-4, -galleryD*0.25), half: new THREE.Vector2(0.7, 0.5) },
      { pos: new THREE.Vector2( 3.2, -galleryD*0.55), half: new THREE.Vector2(0.5, 0.5) },
    ]
    const resolveObstacles = (nx:number, nz:number) => {
      let rx = nx, rz = nz
      const all = obstacles.concat(dynamicObstacles)
      for (const o of all) {
        // AABB with padding by player radius
        const minX = o.pos.x - o.half.x - playerRadius
        const maxX = o.pos.x + o.half.x + playerRadius
        const minZ = o.pos.y - o.half.y - playerRadius
        const maxZ = o.pos.y + o.half.y + playerRadius
        if (rx > minX && rx < maxX && rz > minZ && rz < maxZ) {
          // Push out along the smallest penetration axis
          const px = Math.min(maxX - rx, rx - minX)
          const pz = Math.min(maxZ - rz, rz - minZ)
          if (px < pz) {
            rx = (rx - o.pos.x) > 0 ? maxX : minX
          } else {
            rz = (rz - o.pos.y) > 0 ? maxZ : minZ
          }
        }
      }
      return { x: rx, z: rz }
    }
    const GRAVITY = 28
    let canJump = false
    let prev = performance.now()

    const animate = () => {
      const now = performance.now()
      const delta = Math.min((now - prev) / 1000, 0.05)
      prev = now

      // s1.rotation.y += 0.4 * delta
      // s2.rotation.y += 0.2 * delta
      // s3.rotation.y += 0.3 * delta

      velocity.x -= velocity.x * 10.0 * delta
      velocity.z -= velocity.z * 10.0 * delta
      velocity.y -= GRAVITY * delta

      direction.z = Number(keys.w) - Number(keys.s)
      direction.x = Number(keys.d) - Number(keys.a)
      direction.normalize()

      const speed = 6.0
      if (keys.w || keys.s) velocity.z -= direction.z * speed
      if (keys.a || keys.d) velocity.x -= direction.x * speed

      // Intended next position
      let nextX = camera.position.x + velocity.x * delta
      let nextZ = camera.position.z + velocity.z * delta

      // Corridor bounds
      nextX = THREE.MathUtils.clamp(nextX, bounds.minX, bounds.maxX)
      nextZ = THREE.MathUtils.clamp(nextZ, bounds.minZ, bounds.maxZ)

      // Resolve obstacles
      const resolved = resolveObstacles(nextX, nextZ)
      camera.position.x = resolved.x
      camera.position.z = resolved.z
      camera.position.y += velocity.y * delta

      if (camera.position.y < 1.7) { velocity.y = 0; camera.position.y = 1.7; canJump = true }
      if (keys.space && canJump) { velocity.y += 10; canJump = false }

      // 计算移动向量（如需用于其他逻辑）并记录上一帧位置
      const currentPos = new THREE.Vector3(camera.position.x, 0, camera.position.z)
      const moveDir = new THREE.Vector3().subVectors(currentPos, prevPosition)
      void moveDir
      prevPosition.copy(currentPos)
      
      // 实时检测附近可交互的相框
      let closestFrame: { imageUrl: string; distance: number } | null = null
      let minDistance = MAX_INTERACT_DISTANCE
      
      for (const frame of frameMeshes) {
        const distance = getFrameDistance(frame.mesh)
        if (distance < minDistance) {
          minDistance = distance
          closestFrame = { imageUrl: frame.imageUrl, distance }
        }
      }
      
      setNearbyFrame(closestFrame)
      
      // Update position state for UI display
      setPosition({
        x: parseFloat(camera.position.x.toFixed(2)),
        y: parseFloat(camera.position.y.toFixed(2)),
        z: parseFloat(camera.position.z.toFixed(2))
      })

      renderer.render(scene, camera)
      raf = requestAnimationFrame(animate)
    }
    let raf = requestAnimationFrame(animate)

    const onResize = () => {
      camera.aspect = window.innerWidth / window.innerHeight
      camera.updateProjectionMatrix()
      renderer.setSize(window.innerWidth, window.innerHeight)
    }
    window.addEventListener('resize', onResize)

    return () => {
      cancelAnimationFrame(raf)
      window.removeEventListener('resize', onResize)
      window.removeEventListener('keydown', onKeyDown)
      window.removeEventListener('keyup', onKeyUp)
      overlay?.removeEventListener('click', lock)
      renderer.domElement.removeEventListener('click', handleClick)
      try {
        if (renderer?.domElement?.parentNode) {
          (renderer.domElement.parentNode as HTMLElement).removeChild(renderer.domElement)
        }
        renderer?.dispose?.()
      } catch {}
    }
  }, [])

  return (
    <div style={{ position: 'fixed', inset: 0, background: '#0a1a2a' }}>
      <div ref={mountRef} style={{ width: '100%', height: '100%' }} />
      {/* 位置信息显示 */}
      <div style={{
        position: 'absolute',
        top: '20px',
        left: '20px',
        padding: '12px 16px',
        background: 'rgba(10, 26, 42, 0.85)',
        border: '1px solid rgba(120, 188, 255, 0.3)',
        borderRadius: '8px',
        color: '#cfe9ff',
        fontFamily: 'monospace',
        fontSize: '14px',
        zIndex: 100,
        backdropFilter: 'blur(8px)',
        boxShadow: '0 4px 12px rgba(0, 0, 0, 0.3)'
      }}>
        <div style={{ marginBottom: '8px', fontSize: '12px', opacity: 0.8, borderBottom: '1px solid rgba(120, 188, 255, 0.2)', paddingBottom: '6px' }}>
          位置信息
        </div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: '4px' }}>
          <div>X: <span style={{ color: '#78bcff' }}>{position.x}</span></div>
          <div>Y: <span style={{ color: '#78bcff' }}>{position.y}</span></div>
          <div>Z: <span style={{ color: '#78bcff' }}>{position.z}</span></div>
        </div>
      </div>
      
      {/* 附近照片提示 */}
      {nearbyFrame && (
        <div style={{
          position: 'absolute',
          bottom: '30px',
          left: '50%',
          transform: 'translateX(-50%)',
          padding: '10px 20px',
          background: 'rgba(10, 26, 42, 0.9)',
          border: '1px solid rgba(120, 188, 255, 0.5)',
          borderRadius: '8px',
          color: '#cfe9ff',
          fontSize: '14px',
          zIndex: 100,
          backdropFilter: 'blur(8px)',
          boxShadow: '0 4px 12px rgba(0, 0, 0, 0.4)',
          textAlign: 'center'
        }}>
          <div style={{ marginBottom: '4px', fontWeight: 'bold', color: '#78bcff' }}>
            点击查看照片
          </div>
          <div style={{ fontSize: '12px', opacity: 0.8 }}>
            距离: {nearbyFrame.distance.toFixed(1)}m
          </div>
        </div>
      )}
      <div ref={overlayRef} style={{ position:'absolute', inset:0, display:'flex', alignItems:'center', justifyContent:'center', color:'#cfe9ff', cursor:'pointer' }}>
        <div style={{ padding:'18px 22px', border:'1px solid rgba(120,188,255,0.4)', borderRadius:12, background:'linear-gradient(180deg, rgba(12,36,66,0.8), rgba(8,22,40,0.9))' }}>
          <div style={{ fontSize:18, textAlign:'center' }}>点击进入展厅</div>
          <div style={{ marginTop:6, fontSize:14, opacity:.9 }}>WASD 移动 · 鼠标视角</div>
          <div style={{ marginTop:6, fontSize:14, opacity:.9 }}>空格跳跃 · 点击相框查看图片</div>
        </div>
      </div>
      
      {/* 图片查看器模态框 */}
      {selectedImage && (
        <div 
          style={{
            position: 'fixed',
            inset: 0,
            background: 'rgba(0, 0, 0, 0.9)',
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            zIndex: 9999,
            cursor: 'pointer'
          }}
          onClick={() => setSelectedImage(null)}
        >
          <div style={{ position: 'relative', maxWidth: '90vw', maxHeight: '90vh' }}>
            <img 
              src={selectedImage} 
              alt="查看图片" 
              style={{ 
                maxWidth: '100%', 
                maxHeight: '90vh', 
                objectFit: 'contain',
                borderRadius: '8px'
              }} 
            />
            <div 
              style={{
                position: 'absolute',
                top: '10px',
                right: '10px',
                background: 'rgba(0, 0, 0, 0.7)',
                color: 'white',
                border: 'none',
                borderRadius: '50%',
                width: '40px',
                height: '40px',
                display: 'flex',
                alignItems: 'center',
                justifyContent: 'center',
                cursor: 'pointer',
                fontSize: '24px',
                lineHeight: '1'
              }}
              onClick={(e) => {
                e.stopPropagation()
                setSelectedImage(null)
              }}
            >
              ×
            </div>
          </div>
          <div style={{
            position: 'absolute',
            bottom: '20px',
            left: '50%',
            transform: 'translateX(-50%)',
            color: 'white',
            background: 'rgba(0, 0, 0, 0.7)',
            padding: '8px 16px',
            borderRadius: '4px',
            fontSize: '14px'
          }}>
            点击任意处关闭
          </div>
        </div>
      )}
    </div>
  )
}

export default Index
